<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta charset="utf-8" /></head>

<style type="text/css">
html, body {
padding: 0;
max-width: 900px;
height: 100%;
border: none;
background-color: #F4F8FD;
font-family:Verdana, Arial, Helvetica, sans-serif;
}
div.body{
	border: 1px solid #E0E4EC;
	background-color: #F4F8FD;
}
h1{
	text-align: center;
}
h3{
	text-align: left;
}
div.leftcolum {
float: left;
}
div.rightcolum {
float: right;
}
span.vline {
	border-left: thin solid #CDBFDC;
	border-right: thin solid #CDBFDC;
}
span.hlred {
	font-weight : bold;
	color : #FF0000;
}
table {
	width: 100%;
}
table.textwrap { 
	width: 1px;
	margin: 5px;
}
table.topsection{
	border: 1px solid #CDB;
	background-color: #DEC;
}
td.textleft { text-align: left; }
td.textright { text-align: right; }

SPAN.PermiPrefix { color: #008080 }
SPAN.DataPrefix { color: #22EEAA }
SPAN.CodeStruct { color: #CC00FF; font-weight: bold; }
SPAN.DataType { color: #10CC20 }
SPAN.StmtKey { color: #FF9900; font-weight: bold; }
SPAN.Comment { color: #0066FF; font-style: italic; }
SPAN.String { color: #FF0066 }
SPAN.Number { color: #FF0044 }
SPAN.Method { color: #448800 }
SPAN.SpecSymbol { color: #999900 }
.text_italic { font-style: italic; }
.text_bold { font-weight: bold; }
.text_delete { text-decoration: centerline; }
.text_underline { text-decoration: underline; }
.flushright{ text-align: right; }
.bold{ font-weight: bold; }
.vspace{ padding: 0.3em 0.3em; }
span.codeback{
	background-color: #cda;
}

TABLE.boardHeader {
	padding: 8px 2px;
	background-color: #D5EFDC;
	width: 100%;
}

div.hlcode {
	background-color: #E8F8F8;
	margin: 5px;
	padding : 5px;
	width: 90%;
	margin-left	: 5%;
	margin-right : 5%;
	border: 2px dashed #bdc;
}
TABLE.outputTable {
	background-color: #D8FEFE;
	width: 90%;
	margin-left	: 5%;
	margin-right : 5%;
}
.sdmltable {
	background-color: #F8E8FB;
	width: 90%;
	margin-left	: 5%;
	margin-right : 5%;
	border: 1px solid #CCCCCC;
}
.docTableRow {
	padding: 10px 10px;
	background-color: #F4EEFB;
}
.docTableCell {
	background-color: #F8EEFB;
	padding-right  : 10px;
	padding-top	: 2px;
	padding-left   : 10px;
	padding-bottom : 2px;
	border: 1px solid #CCCCCC;
}

</style>
<body><div class="body">

<h2>使用道语言作网站编程</h2>
<div align=center><p><b>傅利民(phoolimin<img src="/images/at.png"/>gmail<img src="/images/dot.png"/>com)</b></p></div>
<table class=toc><tr><td><ol><li style="margin-top: 5px"><a href="#1">使用CGI模块</a></li>
<li style="margin-top: 5px"><a href="#2">数据库处理</a></li>
<li style="margin-top: 5px"><a href="#3">简单的模型(Model)与视图(View)分离</a></li>
</ol></td></tr></table> <br/><br/>
本文档将不介绍如何进行网站编程，而仅介绍如何将道语言用作服务器端脚本语言。
服务端脚本程序主要是通过公共网关协议（Common Gateway Interface，CGI）
来与网站服务器程序协作。
脚本程序通过CGI获取HTTP请求的有关信息，然后决定如何回应。
一般情况下，脚本程序还需要查询数据库并将结果以恰当的方式反馈给
客户端网页浏览器。<br/>
<table class="topsection"><tr><td><a name="1"><H3>1  使用CGI模块</H3>
</td><td align="right"><a href="&section=1"></a>&nbsp;<a href="#start">top</a></td></tr></table>
 <br/>
DaoCGI是一个用来解析HTTP请求信息的模块，它将解析的结果以结构化的
数据（道语言变量）形式供脚本程序使用。<br/><br/>
载入DaoCGI：
<div class="hlcode">
<span class=StmtKey>load</span>&thinsp; DaoCGI;</div>
 
载入后，当前的名字空间将增加如下全局变量：

<table class="sdmltable">
<tr><th> 变量名</th><th> 类型</th><th> 含义</th></tr>
<tr class=docTableRow><td class=docTableCell> HTTP_ENV</td><td class=docTableCell> map&lt;string,string&gt;</td><td class=docTableCell> HTTP请求的环境变量</td></tr>
<tr class=docTableRow><td class=docTableCell> HTTP_GET</td><td class=docTableCell> map&lt;string,string&gt;</td><td class=docTableCell> GET请求的变量</td></tr>
<tr class=docTableRow><td class=docTableCell> HTTP_POST</td><td class=docTableCell> map&lt;string,string&gt;</td><td class=docTableCell> POST请求的变量</td></tr>
<tr class=docTableRow><td class=docTableCell> HTTP_GETS</td><td class=docTableCell> map&lt;string,list&lt;string&gt; &gt;</td><td class=docTableCell> GET请求的变量</td></tr>
<tr class=docTableRow><td class=docTableCell> HTTP_POSTS</td><td class=docTableCell> map&lt;string,list&lt;string&gt; &gt;</td><td class=docTableCell> POST请求的变量</td></tr>
<tr class=docTableRow><td class=docTableCell> HTTP_COOKIE</td><td class=docTableCell> map&lt;string,string&gt;</td><td class=docTableCell> 请求所附带的cookies</td></tr>
<tr class=docTableRow><td class=docTableCell> HTTP_FILE</td><td class=docTableCell> map&lt;string,stream&gt;</td><td class=docTableCell> 请求所上传的文件</td></tr>
</table>
 
对于HTTP_GETS和HTTP_POSTS，里面可能包含同一个键的多个值。
对于HTTP_FILE其元素的键是文件的上传名，
<div class="hlcode">
&lt;input&thinsp; type=<span class=String>"file"</span>&thinsp; name=<span class=String>"上传名"</span>&thinsp; id=<span class=String>"filename"</span>/&gt;</div>
 
而元素的值是流对象，其中内容是上传的文件的数据。<br/><br/>
一个简单的CGI程序，
<div class="hlcode">
<span class=StmtKey>load</span>&thinsp; DaoCGI;<br/><span class=Method>stdio.println</span><span class=SpecSymbol>(</span>&thinsp; <span class=String>'content-type: text/plain\n'</span>&thinsp; <span class=SpecSymbol>)</span>;<br/><span class=Method>stdio.println</span><span class=SpecSymbol>(</span>&thinsp; <span class=String>'You are from:'</span>,&thinsp; <span class=Number>HTTP_ENV</span><span class=SpecSymbol>[</span>&thinsp; <span class=String>'REMOTE_ADDR'</span>&thinsp; <span class=SpecSymbol>]</span>&thinsp; <span class=SpecSymbol>)</span>;<br/><span class=Method>stdio.println</span><span class=SpecSymbol>(</span>&thinsp; <span class=String>'Welcome to visit:'</span>,&thinsp; <span class=Number>HTTP_ENV</span><span class=SpecSymbol>[</span><span class=String>'REQUEST_URI'</span><span class=SpecSymbol>]</span>&thinsp; <span class=SpecSymbol>)</span>;</div>
 <br/>
<table class="topsection"><tr><td><a name="2"><H3>2  数据库处理</H3>
</td><td align="right"><a href="&section=2"></a>&nbsp;<a href="#start">top</a></td></tr></table>
 <br/>
目前道语言还只有处理MYSQL数据库的模块，
其处理方式是将道语言类映射到数据库表上，
建立类成员到表域名的对应关系，
然后通过类实例操作数据库表里的记录。
请参看更详细的文档<a href="/page/dao_datamodel_zh">使用DaoDataModel模块处理数据库</a> 。<br/>
<table class="topsection"><tr><td><a name="3"><H3>3  简单的模型(Model)与视图(View)分离</H3>
</td><td align="right"><a href="&section=3"></a>&nbsp;<a href="#start">top</a></td></tr></table>
 <br/>
通常情况下，服务端脚本程序要负责生成HTML代码以在网页浏览器里显示信息。
这些信息或数据一般被保存在服务器上的文件或数据库里，
脚本程序也要负责这些数据的处理，此即为模型部分。
当这些数据需要被显示在客户端的浏览器里时，
脚本程序需要生成合适的HTML代码以达到恰当可视化效果，
这就是视图部分。<br/><br/>
显然程序的模型部分和视图部分最好是分离的，这样对一个部分的修改
将不影响另一个部分。这使得程序的维护和升级更加简单安全。
道语言的DaoDataModel比较适合处理程序的模型部分，
而道语言的一些字符串方法将使得视图部分也比较简单。
下面将以一个例子来作介绍。<br/><br/>
假设有一个名为Friend的数据库表，它保存着包含如下信息的地址簿：
<div class="hlcode">
id&thinsp; &thinsp; :&thinsp; <span class=Number>INTEGER</span>&thinsp; <span class=Number>PRIMARY</span>&thinsp; <span class=Number>KEY</span>&thinsp; <span class=Number>AUTOINCREMENT</span><br/>name&thinsp; &thinsp; :&thinsp; <span class=Number>CHAR</span><span class=SpecSymbol>(</span><span class=Number>50</span><span class=SpecSymbol>)</span><br/>phone&thinsp; :&thinsp; <span class=Number>CHAR</span><span class=SpecSymbol>(</span><span class=Number>20</span><span class=SpecSymbol>)</span><br/>city&thinsp; &thinsp; :&thinsp; <span class=Number>CHAR</span><span class=SpecSymbol>(</span><span class=Number>50</span><span class=SpecSymbol>)</span><br/>street&thinsp; :&thinsp; <span class=Number>VARCHAR</span><span class=SpecSymbol>(</span><span class=Number>100</span><span class=SpecSymbol>)</span></div>
 <br/>
其对应的道语言类是:
<div class="hlcode">
<span class=CodeStruct>typedef</span>&thinsp; <span class=DataType>tuple</span>&lt;id:<span class=DataType>string</span>,name:<span class=DataType>string</span>,phone:<span class=DataType>string</span>,city:<span class=DataType>string</span>,street:<span class=DataType>string</span>&gt;&thinsp; friend_t;<br/><br/><span class=CodeStruct>class</span>&thinsp; Friend<br/><span class=SpecSymbol>{</span><br/>&nbsp;&nbsp;&nbsp;&nbsp; <span class=DataPrefix>my</span>&thinsp; id&thinsp; :&thinsp; <span class=Number>INT_PRIMARY_KEY_AUTOINCREMENT</span>;<br/>&nbsp;&nbsp;&nbsp;&nbsp; <span class=DataPrefix>my</span>&thinsp; name&thinsp; &thinsp; :&thinsp; <span class=Number>CHAR50</span>;<br/>&nbsp;&nbsp;&nbsp;&nbsp; <span class=DataPrefix>my</span>&thinsp; phone&thinsp; :&thinsp; <span class=Number>CHAR20</span>;<br/>&nbsp;&nbsp;&nbsp;&nbsp; <span class=DataPrefix>my</span>&thinsp; city&thinsp; &thinsp; :&thinsp; <span class=Number>CHAR50</span>;<br/>&nbsp;&nbsp;&nbsp;&nbsp; <span class=DataPrefix>my</span>&thinsp; street&thinsp; :&thinsp; <span class=Number>CHAR100</span>;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp; <span class=CodeStruct>routine</span>&thinsp; AsTuple<span class=SpecSymbol>(</span><span class=SpecSymbol>)</span>&thinsp; <span class=SpecSymbol>=></span>&thinsp; friend_t&thinsp; <span class=SpecSymbol>{</span><br/>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; <span class=StmtKey>return</span>&thinsp; <span class=SpecSymbol>(</span>&thinsp; <span class=SpecSymbol>(</span><span class=DataType>string</span><span class=SpecSymbol>)</span>&thinsp; id,&thinsp; name,&thinsp; phone,&thinsp; city,&thinsp; street&thinsp; <span class=SpecSymbol>)</span>;<br/>&nbsp;&nbsp;&nbsp;&nbsp; <span class=SpecSymbol>}</span><br/><span class=SpecSymbol>}</span></div>
 
这里还定义了一个元组类型friend_t，它包含了带名称的元素。
这个元组类型将是程序的模型部分与视图部分传递数据的基本数据结构。<br/><br/>
再假设，相关数据库被打开为：
<div class="hlcode">
<span class=DataPrefix>global</span>&thinsp; model&thinsp; =&thinsp; DataModel<span class=SpecSymbol>(</span>&thinsp; <span class=String>'dbname'</span>,&thinsp; <span class=String>'host'</span>,&thinsp; <span class=String>'user'</span>,&thinsp; <span class=String>'password'</span>&thinsp; <span class=SpecSymbol>)</span>;</div>
 <br/>
现在在模型部分，数据库的查询将变得很简单。
例如，如果要显示某个城市里的所有朋友，可以这样做：
<div class="hlcode">
<span class=CodeStruct>routine</span>&thinsp; FriendInCity<span class=SpecSymbol>(</span>&thinsp; city&thinsp; :&thinsp; <span class=DataType>string</span>&thinsp; <span class=SpecSymbol>)</span>&thinsp; <span class=SpecSymbol>=></span>&thinsp; <span class=DataType>list</span>&lt;friend_t&gt;<br/><span class=SpecSymbol>{</span><br/>&nbsp;&nbsp;&nbsp;&nbsp; friends&thinsp; =&thinsp; <span class=SpecSymbol>{</span><span class=SpecSymbol>}</span>;<br/>&nbsp;&nbsp;&nbsp;&nbsp; friend&thinsp; =&thinsp; Friend<span class=SpecSymbol>(</span><span class=SpecSymbol>)</span>;<br/>&nbsp;&nbsp;&nbsp;&nbsp; hd&thinsp; =&thinsp; model.Select<span class=SpecSymbol>(</span>&thinsp; Friend&thinsp; <span class=SpecSymbol>)</span>.Where<span class=SpecSymbol>(</span><span class=SpecSymbol>)</span>.<span class=Number>EQ</span><span class=SpecSymbol>(</span>&thinsp; <span class=String>'city'</span>,&thinsp; city&thinsp; <span class=SpecSymbol>)</span>;<br/>&nbsp;&nbsp;&nbsp;&nbsp; <span class=StmtKey>while</span><span class=SpecSymbol>(</span>&thinsp; hd.Query<span class=SpecSymbol>(</span>&thinsp; friend&thinsp; <span class=SpecSymbol>)</span>&thinsp; <span class=SpecSymbol>)</span>&thinsp; friends.<span class=Method>append</span><span class=SpecSymbol>(</span>&thinsp; friend.AsTuple<span class=SpecSymbol>(</span><span class=SpecSymbol>)</span>&thinsp; <span class=SpecSymbol>)</span>;<br/>&nbsp;&nbsp;&nbsp;&nbsp; hd.Done<span class=SpecSymbol>(</span><span class=SpecSymbol>)</span>;<br/>&nbsp;&nbsp;&nbsp;&nbsp; <span class=StmtKey>return</span>&thinsp; friends;<br/><span class=SpecSymbol>}</span></div>
 
显然这个函数也可被定义为Friend类的成员方法。<br/><br/>
数据视图的创建可以使用模板HTML代码进行简化。
例如，如果需要在一个表单里显示所有被查询的朋友，
可以定义如下HTML模板：
<div class="hlcode">
&lt;tr&thinsp; <span class=CodeStruct>class</span>=<span class=String>"myrowstyle"</span>&gt;&lt;td&thinsp; <span class=CodeStruct>class</span>=<span class=String>"mycellstyle"</span>&gt;@<span class=SpecSymbol>(</span>id<span class=SpecSymbol>)</span>&lt;/td&gt;<br/>&lt;td&gt;@<span class=SpecSymbol>(</span>name<span class=SpecSymbol>)</span>&lt;/td&gt;&lt;td&gt;@<span class=SpecSymbol>(</span>phone<span class=SpecSymbol>)</span>&lt;/td&gt;<br/>&lt;td&gt;@<span class=SpecSymbol>(</span>city<span class=SpecSymbol>)</span>&lt;/td&gt;&lt;td&gt;@<span class=SpecSymbol>(</span>street<span class=SpecSymbol>)</span>&lt;/td&gt;&lt;/tr&gt;</div>
 
HTML模板可用来决定显示那些数据，以何种方式显示。
数据文本的字体颜色等也可被包含在模板里，
不过，使用层叠样式表CSS来设置它们更方便。<br/><br/>
视图的创建可以是：
<div class="hlcode">
<span class=CodeStruct>routine</span>&thinsp; ViewFriends<span class=SpecSymbol>(</span>&thinsp; friends&thinsp; :&thinsp; <span class=DataType>list</span>&lt;friend_t&gt;,&thinsp; rowtpl&thinsp; =&thinsp; <span class=String>''</span>&thinsp; <span class=SpecSymbol>)</span><br/><span class=SpecSymbol>{</span><br/>&nbsp;&nbsp;&nbsp;&nbsp; html&thinsp; =&thinsp; <span class=String>'&lt;table class="mytablestyle"&gt;\n'</span>;<br/>&nbsp;&nbsp;&nbsp;&nbsp; <span class=StmtKey>for</span><span class=SpecSymbol>(</span>&thinsp; friend&thinsp; <span class=StmtKey>in</span>&thinsp; friends&thinsp; <span class=SpecSymbol>)</span>&thinsp; html&thinsp; +=&thinsp; rowtpl.expand<span class=SpecSymbol>(</span>&thinsp; friend,&thinsp; <span class=String>'@'</span>&thinsp; <span class=SpecSymbol>)</span>;<br/>&nbsp;&nbsp;&nbsp;&nbsp; html&thinsp; +=&thinsp; <span class=String>'&lt;/table&gt;'</span>;<br/>&nbsp;&nbsp;&nbsp;&nbsp; <span class=StmtKey>return</span>&thinsp; html;<br/><span class=SpecSymbol>}</span></div>
 
这里rowtpl.expand()方法将展开字符串rowtpl，并替换里面的占位变量，
替换内容为元组friend里的跟占位变量同名的元素的值。
expand()还有一个重载的函数，用来接受映射表为参数。<br/><br/>
最后，查询数据库并创建视图可以用，
<div class="hlcode">
row&thinsp; =&thinsp; <span class=String>'&lt;tr class="myrowstyle"&gt;&lt;td class="mycellstyle"&gt;@(id)&lt;/td&gt;
<br />&lt;td&gt;@(name)&lt;/td&gt;&lt;td&gt;@(phone)&lt;/td&gt;
<br />&lt;td&gt;@(city)&lt;/td&gt;&lt;td&gt;@(street)&lt;/td&gt;&lt;/tr&gt;'</span>;<br/><br/>friends&thinsp; =&thinsp; FriendInCity<span class=SpecSymbol>(</span>&thinsp; <span class=String>'Beijing'</span>&thinsp; <span class=SpecSymbol>)</span>;<br/>view&thinsp; =&thinsp; ViewFriends<span class=SpecSymbol>(</span>&thinsp; friends,&thinsp; row&thinsp; <span class=SpecSymbol>)</span>;</div>
 
通过改变模板HTML代码（和CSS），视图的形式和效果可以很容易地被改变。<br clear=all />
</div></body></html>
